package com.catazy.mvvmlib.ext

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.viewbinding.ViewBinding
import com.catazy.mvvmlib.base.BaseApplication
import com.catazy.mvvmlib.base.viewmodel.BaseViewModel
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.ParameterizedType

/**
 * 作者: Tao
 * 日期: 2024/1/25
 * 时间: 9:57
 * 描述: ViewDataBinding + ViewModel的拓展类
 */

/**
 * 在Activity中得到Application上下文的ViewModel
 * 提示，在Activity中调用该方法时，请在该Activity onCreate以后调用或者请用by lazy方式懒加载初始化调用，不然会提示application没有导致错误
 */
inline fun <reified VM : BaseViewModel> AppCompatActivity.getAppViewModel(): VM {
    (this.application as? BaseApplication).let {
        if (it == null) {
            throw NullPointerException("你的Application没有继承BaseApplication，暂时无法使用该方法")
        } else {
            return it.getAppViewModelProvider()[VM::class.java]
        }
    }
}

/**
 * 在Fragment中得到Application上下文的ViewModel
 * 提示，在fragment中调用该方法时，请在该Fragment onCreate以后调用或者请用by lazy方式懒加载初始化调用，不然会提示requireActivity没有导致错误
 */
inline fun <reified VM : BaseViewModel> Fragment.getAppViewModel(): VM {
    (this.requireActivity().application as? BaseApplication).let {
        if (it == null) {
            throw NullPointerException("你的Application没有继承BaseApplication，暂时无法使用该方法")
        } else {
            return it.getAppViewModelProvider()[VM::class.java]
        }
    }
}

/**
 * 得到当前Activity上下文的ViewModel
 *
 */
inline fun <reified VM : BaseViewModel> AppCompatActivity.getViewModel(): VM {
    return ViewModelProvider(
        this,
        ViewModelProvider.AndroidViewModelFactory(application)
    )[VM::class.java]
}

/**
 * 得到当前Fragment上下文的ViewModel
 */
inline fun <reified VM : BaseViewModel> Fragment.getViewModel(): VM {
    return ViewModelProvider(
        this,
        ViewModelProvider.AndroidViewModelFactory(this.requireActivity().application)
    )[VM::class.java]
}

/**
 * 反射获取Activity的ViewBinding实例
 */
@Suppress("UNCHECKED_CAST")
fun <VB : ViewBinding> AppCompatActivity.inflateBindingWithGeneric(): VB {
    return withGenericBindingClass(this) {
        it.getMethod("inflate", LayoutInflater::class.java).invoke(null, layoutInflater) as VB
    }.also {
        if (it is ViewDataBinding) {
            it.lifecycleOwner = this
        }
    }
}

/**
 * 反射获取Fragment的ViewBinding实例
 */
@Suppress("UNCHECKED_CAST")
fun <VB : ViewBinding> Fragment.inflateBindingWithGeneric(
    parent: ViewGroup?,
    attachToParent: Boolean
): VB {
    return withGenericBindingClass(this) {
        it.getMethod(
            "inflate",
            LayoutInflater::class.java,
            ViewGroup::class.java,
            Boolean::class.java
        )
            .invoke(null, layoutInflater, parent, attachToParent) as VB
    }.also {
        if (it is ViewDataBinding) {
            it.lifecycleOwner = viewLifecycleOwner
        }
    }
}

private fun <VB : ViewBinding> withGenericBindingClass(any: Any, block: (Class<VB>) -> VB): VB {
    var genericSuperclass = any.javaClass.genericSuperclass
    var superclass = any.javaClass.superclass
    while (superclass != null) {
        if (genericSuperclass is ParameterizedType) {
            try {
                return block.invoke(genericSuperclass.actualTypeArguments[1] as Class<VB>)
            } catch (e: NoSuchMethodException) {
                throw NoSuchMethodException("There is no inflate method in ViewBinding.")
            } catch (e: ClassCastException) {
                throw ClassCastException("Generic type is not ViewBinding.")
            } catch (e: InvocationTargetException) {
                throw e.targetException
            }
        }
        genericSuperclass = superclass.genericSuperclass
        superclass = superclass.superclass
    }
    throw IllegalArgumentException("There is no generic of ViewBinding.")
}



